#include "paletteNEWER.h"
#include "video.h"
#include <stdio.h>

#define palp(paladdress,ramaddress,colours) { paladdress, ramaddress, colours }
#define SWAPWORD(val) (((val&0x00FF)<<8)+((val&0xFF00)>>8))

extern byte v_zone;

extern byte Pal_SegaBG[];
extern byte Pal_Title[];
extern byte Pal_LevelSel[];
extern byte Pal_Sonic[];
extern byte Pal_GHZ[];

word v_pal_dry[64];
word v_pal_dry_dup[64];

signed short v_pcyc_time;
word v_pcyc_num;

void (*PCycle_Index[7])() = { PCycle_GHZ, 0/*PCycle_LZ*/, 0/*PCycle_MZ*/, 0/*PalCycle_SLZ*/, 0/*PalCycle_SYZ*/, 0/*PalCycle_SBZ*/, PCycle_GHZ };

extern byte Pal_GHZCyc[];

void palToCRAM()
{
    for (int i=0; i<64; i++)
        setfcRam(i/16,i%16,SWAPWORD(v_pal_dry[i]));
}

typedef struct palettePointer
{
    union { byte *paladdress; long palData; };
    union { word *ramaddress; long ramData; };
    word length;
};

palettePointer PalPointers[] = { 
    palp(Pal_SegaBG,   v_pal_dry,      63),      // 0 - Sega logo
    palp(Pal_Title,    v_pal_dry,      63),       // 1 - title screen
    palp(Pal_LevelSel, v_pal_dry,      63),    // 2 - level select
    palp(Pal_Sonic,    v_pal_dry,      15),       // 3 - Sonic
    palp(Pal_GHZ,      v_pal_dry+0x10, 47)         // 4 - GHZ
};

void PalLoad1(word index)        //loads palette (id index) to transition palette buffer, (which is eventually copied to 'main' palette buffer which is transferred to CRAM during vblank)
{
    //PalLoad1:
    //lea	(PalPointers).l,a1
    byte *PalPointersPtr = (byte*)PalPointers;

    //lsl.w	#3,d0
    word PalPointersOffset = index * sizeof(palettePointer);

    //adda.w	d0,a1
    long *PalPointer = (long*)&PalPointersPtr[PalPointersOffset];
    
    //movea.l	(a1)+,a2	; get palette data address
    word *palData = (word*)*(PalPointer++);

    //movea.w	(a1)+,a3	; get target RAM address
    word *dest = (word*)*(PalPointer++);

    //adda.w	#$80,a3		; skip to "main" RAM address
    dest += 0x40;
 
    //move.w	(a1)+,d7	; get length of palette data
    signed short paldataLength = *((word*)(PalPointer));
	
    int i=0;
    //@loop:
    for (; paldataLength >= 0; paldataLength--, i++)
    {
        word color = *(palData++);
        //setfcRam(palLine+(i/16),i%16,SWAPWORD(color));
        *(dest++) = color;
    }
 
     //move.l	(a2)+,(a3)+	; move data to RAM
     //dbf	d7,@loop
     //rts	
}//; End of function PalLoad1

void PalLoad2(word index)        //loads palette (id index) directly to 'main' palette buffer (which is transferred to CRAM during vblank)
{
    //PalLoad2:
    //lea	(PalPointers).l,a1
    byte *PalPointersPtr = (byte*)PalPointers;

    //lsl.w	#3,d0
    word PalPointersOffset = index * sizeof(palettePointer);

    //adda.w	d0,a1
    long *PalPointer = (long*)&PalPointersPtr[PalPointersOffset];
    
    //movea.l	(a1)+,a2	; get palette data address
    word *palData = (word*)*(PalPointer++);

    //movea.w	(a1)+,a3	; get target RAM address
    word *dest = (word*)*(PalPointer++);
 
    //move.w	(a1)+,d7	; get length of palette data
    signed short paldataLength = *((word*)(PalPointer));
	
    int i=0;
    //@loop:
    for (; paldataLength >= 0; paldataLength--, i++)
    {
        word color = *(palData++);
        //setfcRam(palLine+(i/16),i%16,SWAPWORD(color));
        *(dest++) = color;
    }
 
     //move.l	(a2)+,(a3)+	; move data to RAM
     //dbf	d7,@loop
     //rts	
}//; End of function PalLoad2

void PaletteNoFade()
{
     for (int i=0; i<64; i++)
         v_pal_dry[i] = v_pal_dry_dup[i];
}
void PaletteCycle()
{
    //; ---------------------------------------------------------------------------
    //; Palette cycling routine loading subroutine
    //; ---------------------------------------------------------------------------

    //; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

    //PaletteCycle:				; XREF: GotoDemo; Level_MainLoop; End_MainLoop
    //moveq	#0,d2
    //moveq	#0,d0
   
    //move.b	(v_zone).w,d0	; get level number
    //add.w	d0,d0
    byte zone = v_zone;

    //move.w	PCycle_Index(pc,d0.w),d0
    //jmp	PCycle_Index(pc,d0.w) ; jump to relevant palette routine
    (*PCycle_Index[zone])();
}  //; End of function PaletteCycle

/*; ===========================================================================
; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


PCycle_Title:				; XREF: GM_TitleScr
		lea	(Pal_TitleCyc).l,a0
		bra.s	PCycGHZ_Go
; ===========================================================================*/

void PCycle_GHZ()
{
    //PCycle_GHZ:				; XREF: PCycle_Index
    //lea	(Pal_GHZCyc).l,a0
    long *cycleDataPtr = (long*)Pal_GHZCyc;

    //PCycGHZ_Go:
    //subq.w	#1,(v_pcyc_time).w ; decrement timer
    v_pcyc_time = v_pcyc_time - 1;

    //bpl.s	PCycGHZ_Skip	; if time remains, branch
    if (v_pcyc_time < 0)
    {
        //move.w	#5,(v_pcyc_time).w ; reset timer to 5 frames
	v_pcyc_time = 5;
 
        //move.w	(v_pcyc_num).w,d0 ; get cycle number
        word cycleNum = v_pcyc_num;

	//addq.w	#1,(v_pcyc_num).w ; increment cycle number
        v_pcyc_num = v_pcyc_num + 1;

	//andi.w	#3,d0		; if cycle > 3, reset to 0
        word cycleNumReset = cycleNum & 3;

	//lsl.w	#3,d0
        word cycleDataOffset = cycleNumReset * 2;  //*8 in rom

	//lea	(v_pal_dry+$50).w,a1
        long *palDataPtr = (long*)v_pal_dry + (40/2);

	//move.l	(a0,d0.w),(a1)+
        //move.l	4(a0,d0.w),(a1)	; copy palette data to RAM
        palDataPtr[0] = cycleDataPtr[cycleDataOffset];          //copies 2 longs or
        palDataPtr[1] = cycleDataPtr[cycleDataOffset+1];        //4 words/colors
    }
    //PCycGHZ_Skip:
    //rts	
}//; End of function PCycle_GHZ

long palColor2RGB(word color)
{
     
     word rval=(color&0x0F00)>>8;     //0x000X, X=nybble represent color val
     word gval=(color&0x00F0)>>4;
     word bval=color&0x000F;
     rval*=0xF; gval*=0xF; bval*=0xF;
     
     long finalcolor=(rval)+(gval<<8)+(bval<<16);
     
     return finalcolor;
}
